package com.winsdom.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.winsdom.entity.*;
import com.winsdom.mapper.*;
import com.winsdom.service.IBillingMainService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 计费主表 服务实现类
 * </p>
 *
 * @author
 * @since 2025-05-22
 */
@Service
public class BillingMainServiceImpl extends ServiceImpl<BillingMainMapper, BillingMain> implements IBillingMainService {
    private static final Logger logger = LoggerFactory.getLogger(BillingMainServiceImpl.class);
    private static final DateTimeFormatter PERIOD_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM");
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    // 用于解析包含日的日期格式
    private static final DateTimeFormatter DATE_WITH_DAY_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    // 计费周期常量
    private static final int BILLING_CYCLE_CALENDAR_MONTH = 1;
    private static final int BILLING_CYCLE_CONTRACT_MONTH = 2;

    // 缴费方式常量
    private static final int BILLING_METHOD_CURRENT_MONTH = 1;
    private static final int BILLING_METHOD_NEXT_MONTH = 2;
    private static final int BILLING_METHOD_PREVIOUS_MONTH = 3;

    // 计费性质常量
    private static final int NATURE_PERIODIC = 1; // 周期性计费
    private static final int NATURE_METER = 2;    // 三表类计费

    // 批量处理大小
    private static final int BATCH_SIZE = 1000;
    // 抄表记录状态
    private static final int READING_STATUS_UNBILLED = 0;
    private static final int READING_STATUS_BILLED = 1;

    @Autowired
    private BillingMainMapper billingMainMapper;
    @Autowired
    private ContractMapper contractMapper;
    @Autowired
    private BillingConfigMapper billingConfigMapper;
    @Autowired
    private ExpenditureMapper expenditureMapper;
    @Autowired
    private ReadingRecordMapper readingRecordMapper;
    @Autowired
    private ThreeTablesMapper threeTablesMapper;
    @Autowired
    private BillingDetailMapper billingDetailMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void autoAdd() {
        logger.info("开始执行计费记录生成任务: {}", LocalDate.now());

        try {
            LocalDate currentDate = LocalDate.now();

            // 分页处理合同和配置
            int pageNum = 1;
            boolean hasMoreContracts = true;

            while (hasMoreContracts) {
                // 分页获取有效合同
                List<Contract> contracts = contractMapper.selectPage(
                        new Page<>(pageNum, BATCH_SIZE),
                        new QueryWrapper<Contract>().eq("contract_status", 1)
                ).getRecords();

                if (contracts.isEmpty()) {
                    hasMoreContracts = false;
                    continue;
                }

                // 获取合同ID集合
                Set<Long> contractIds = contracts.stream()
                        .map(Contract::getContractId)
                        .collect(Collectors.toSet());

                // 获取周期性和三表计费配置
                List<BillingConfig> configs = billingConfigMapper.selectBillingConfigsWithExpenditure(
                        contractIds,
                        Arrays.asList(NATURE_PERIODIC, NATURE_METER),
                        1 // 启用状态
                );

                // 按合同ID分组配置
                Map<Long, List<BillingConfig>> configMap = configs.stream()
                        .collect(Collectors.groupingBy(BillingConfig::getContractId));

                // 处理每个合同及其配置
                for (Contract contract : contracts) {
                    List<BillingConfig> contractConfigs = configMap.getOrDefault(contract.getContractId(), Collections.emptyList());
                    if (contractConfigs.isEmpty()) {
                        continue;
                    }

                    // 计算计费记录
                    List<BillingMain> records = calculateBillingRecords(contract, contractConfigs, currentDate);

                    // 保存计费记录
                    if (!records.isEmpty()) {
                        saveBillingRecordsToMainTable(records);

                        // 处理三表计费的明细记录
                        processMeterBillingDetails(records, contractConfigs, currentDate);
                    }
                }

                pageNum++;
            }

            logger.info("计费记录生成任务完成");
        } catch (Exception e) {
            logger.error("执行计费记录生成任务时出错", e);
            throw new RuntimeException("计费记录生成失败", e);
        }
    }

    /**
     * 处理三表计费的明细记录
     */
    private void processMeterBillingDetails(List<BillingMain> records,
                                            List<BillingConfig> contractConfigs,
                                            LocalDate currentDate) {
        if (records.isEmpty() || contractConfigs.isEmpty()) {
            return;
        }

        // 过滤出三表计费的主记录
        List<BillingMain> meterBillingRecords = records.stream()
                .filter(record -> {
                    // 通过合同ID和费项ID查找对应的配置
                    BillingConfig config = findConfigByContractAndExpenditure(
                            record.getContractId(),
                            record.getExpenditureId(),
                            contractConfigs
                    );
                    return config != null &&
                            config.getTableId() != null &&
                            isMeterExpenditure(config.getExpenditureId());
                })
                .collect(Collectors.toList());

        if (meterBillingRecords.isEmpty()) {
            return;
        }

        // 获取所有三表ID
        Set<Integer> tableIds = new HashSet<>();
        for (BillingMain record : meterBillingRecords) {
            BillingConfig config = findConfigByContractAndExpenditure(
                    record.getContractId(),
                    record.getExpenditureId(),
                    contractConfigs
            );
            if (config != null && config.getTableId() != null) {
                tableIds.add(config.getTableId());
            }
        }

        if (tableIds.isEmpty()) {
            return;
        }

        // 获取三表信息
        Map<Integer, ThreeTables> tableMap = threeTablesMapper.selectList(
                        new QueryWrapper<ThreeTables>().in("id", tableIds)
                ).stream()
                .collect(Collectors.toMap(ThreeTables::getId, table -> table));

        // 按账期和三表ID分组处理
        Map<String, Map<Integer, List<BillingMain>>> periodTableMap = new HashMap<>();
        for (BillingMain record : meterBillingRecords) {
            BillingConfig config = findConfigByContractAndExpenditure(
                    record.getContractId(),
                    record.getExpenditureId(),
                    contractConfigs
            );
            if (config == null || config.getTableId() == null) {
                continue;
            }

            periodTableMap.computeIfAbsent(record.getBillingPeriod(), k -> new HashMap<>())
                    .computeIfAbsent(config.getTableId(), k -> new ArrayList<>())
                    .add(record);
        }

        // 处理每个账期和三表的计费明细
        for (Map.Entry<String, Map<Integer, List<BillingMain>>> periodEntry : periodTableMap.entrySet()) {
            String billingPeriod = periodEntry.getKey();
            YearMonth yearMonth = YearMonth.parse(billingPeriod, PERIOD_FORMATTER);
            LocalDate periodStart = yearMonth.atDay(1);
            LocalDate periodEnd = yearMonth.atEndOfMonth();

            for (Map.Entry<Integer, List<BillingMain>> tableEntry : periodEntry.getValue().entrySet()) {
                Integer tableId = tableEntry.getKey();
                List<BillingMain> mainRecords = tableEntry.getValue();

                if (mainRecords.isEmpty()) {
                    continue;
                }

                // 获取该三表在该账期的抄表记录
                ReadingRecord readingRecord = getValidReadingRecord(tableId, periodStart, periodEnd);
                if (readingRecord == null) {
                    logger.warn("未找到三表ID={},账期={}的有效抄表记录", tableId, billingPeriod);
                    continue;
                }

                // 获取三表信息
                ThreeTables threeTable = tableMap.get(tableId);
                if (threeTable == null) {
                    logger.warn("未找到三表ID={}的信息", tableId);
                    continue;
                }

                // 计算用量
                BigDecimal usage = calculateUsage(readingRecord, threeTable.getMagnification());
                if (usage == null || usage.compareTo(BigDecimal.ZERO) <= 0) {
                    logger.warn("三表ID={},账期={}的用量计算错误: {}", tableId, billingPeriod, usage);
                    continue;
                }

                // 处理每条主记录
                for (BillingMain mainRecord : mainRecords) {
                    BillingConfig config = findConfigByContractAndExpenditure(
                            mainRecord.getContractId(),
                            mainRecord.getExpenditureId(),
                            contractConfigs
                    );
                    if (config == null) {
                        continue;
                    }

                    // 生成计费明细
                    BillingDetail detail = createBillingDetail(
                            mainRecord, threeTable, readingRecord,
                            periodStart, periodEnd, usage, config
                    );

                    // 保存明细记录
                    billingDetailMapper.insert(detail);
                }

                // 更新抄表记录状态为已计费
                updateReadingRecordStatus(readingRecord.getId());
            }
        }
    }

    /**
     * 通过合同ID和费项ID查找配置
     */
    private BillingConfig findConfigByContractAndExpenditure(
            Long contractId, Integer expenditureId, List<BillingConfig> configs) {
        if (contractId == null || expenditureId == null || configs == null) {
            return null;
        }

        return configs.stream()
                .filter(config -> contractId.equals(config.getContractId()) &&
                        expenditureId.equals(config.getExpenditureId()))
                .findFirst()
                .orElse(null);
    }

    /**
     * 检查是否为三表类费项
     */
    private boolean isMeterExpenditure(Integer expenditureId) {
        if (expenditureId == null) {
            return false;
        }

        Expenditure expenditure = expenditureMapper.selectById(expenditureId);
        return expenditure != null && expenditure.getNature() == NATURE_METER;
    }

    /**
     * 创建计费明细（从配置中获取三表信息）
     */
    private BillingDetail createBillingDetail(
            BillingMain mainRecord, ThreeTables table, ReadingRecord record,
            LocalDate periodStart, LocalDate periodEnd, BigDecimal usage, BillingConfig config) {
        BillingDetail detail = new BillingDetail();
        detail.setBillingMainId(mainRecord.getId());
        detail.setMeterName(table.getName());
        detail.setMeterNo(table.getNumber());
        detail.setMeterType(getMeterTypeName(table.getType()));
        detail.setMeterRatio(table.getMagnification() != null ?
                new BigDecimal(table.getMagnification()) : BigDecimal.ONE);
        detail.setLastUsage(record.getLastReading() != null ?
                new BigDecimal(record.getLastReading()) : BigDecimal.ZERO);
        detail.setLastRecordTime(record.getLastReadTime());
        detail.setLastReading(record.getLastReading() != null ?
                new BigDecimal(record.getLastReading()) : BigDecimal.ZERO);
        detail.setCurrentReading(record.getCurrentReading() != null ?
                new BigDecimal(record.getCurrentReading()) : BigDecimal.ZERO);
        detail.setUsageAmount(usage);

        // 从配置中获取单价
        detail.setUnitPrice(config.getUnitPrice());

        detail.setStartDate(periodStart);
        detail.setEndDate(periodEnd);

        return detail;
    }

    /**
     * 获取三表类型名称
     */
    private String getMeterTypeName(int type) {
        switch (type) {
            case 0:
                return "水表";
            case 1:
                return "电表";
            case 2:
                return "气表";
            default:
                return "未知";
        }
    }

    /**
     * 获取有效的抄表记录
     */
    private ReadingRecord getValidReadingRecord(Integer tableId, LocalDate periodStart, LocalDate periodEnd) {
        // 查询该三表在账期内的抄表记录
        LambdaQueryWrapper<ReadingRecord> queryWrapper = new LambdaQueryWrapper<ReadingRecord>()
                .eq(ReadingRecord::getTableId, tableId)
                .eq(ReadingRecord::getStatus, READING_STATUS_UNBILLED)
                .between(ReadingRecord::getReadTime,
                        LocalDateTime.of(periodStart, LocalDateTime.MIN.toLocalTime()),
                        LocalDateTime.of(periodEnd, LocalDateTime.MAX.toLocalTime()))
                .orderByDesc(ReadingRecord::getReadTime)
                .last("LIMIT 1");

        return readingRecordMapper.selectOne(queryWrapper);
    }

    /**
     * 计算用量
     */
    private BigDecimal calculateUsage(ReadingRecord record, Integer magnification) {
        if (record.getCurrentReading() == null || record.getLastReading() == null) {
            return null;
        }

        BigDecimal magnificationBD = magnification != null ?
                BigDecimal.valueOf(magnification) : BigDecimal.ONE;
        return new BigDecimal(record.getCurrentReading())
                .subtract(new BigDecimal(record.getLastReading()))
                .multiply(magnificationBD);
    }

    /**
     * 更新抄表记录状态
     */
    private void updateReadingRecordStatus(Integer recordId) {
        ReadingRecord record = new ReadingRecord();
        record.setId(recordId);
        record.setStatus(READING_STATUS_BILLED);
        readingRecordMapper.updateById(record);
    }

    /**
     * 计算单个合同的计费记录
     */
    private List<BillingMain> calculateBillingRecords(Contract contract, List<BillingConfig> configs, LocalDate currentDate) {
        List<BillingMain> billingRecords = new ArrayList<>();

        for (BillingConfig config : configs) {
            // 处理开始日期为空或晚于当前日期的情况
            if (config.getStartDate() == null || config.getStartDate().isAfter(currentDate)) {
                continue;
            }

            // 根据计费周期处理
            BillingCycleProcessor processor = getBillingCycleProcessor(contract.getBillingCycle());
            if (processor != null) {
                processor.process(contract, config, currentDate, billingRecords);
            }
        }

        return billingRecords;
    }

    /**
     * 获取计费周期处理器
     */
    private BillingCycleProcessor getBillingCycleProcessor(int billingCycle) {
        switch (billingCycle) {
            case BILLING_CYCLE_CALENDAR_MONTH:
                return new CalendarMonthProcessor();
            case BILLING_CYCLE_CONTRACT_MONTH:
                return new ContractMonthProcessor();
            default:
                logger.warn("未知的计费周期类型: {}", billingCycle);
                return null;
        }
    }

    /**
     * 计费周期处理器接口
     */
    private interface BillingCycleProcessor {
        void process(Contract contract, BillingConfig config, LocalDate currentDate, List<BillingMain> records);
    }

    /**
     * 自然月计费处理器
     */
    private class CalendarMonthProcessor implements BillingCycleProcessor {
        @Override
        public void process(Contract contract, BillingConfig config, LocalDate currentDate, List<BillingMain> records) {
            LocalDate startDate = config.getStartDate();
            int billingMethod = config.getBillingMethod();
            Integer expenditureId = config.getExpenditureId();

            // 验证费项类型
            if (expenditureId != null) {
                Expenditure expenditure = expenditureMapper.selectById(expenditureId);
                if (expenditure == null ||
                        !Arrays.asList(NATURE_PERIODIC, NATURE_METER).contains(expenditure.getNature())) {
                    logger.warn("费项ID={}类型无效，跳过计费", expenditureId);
                    return;
                }
            }

            // 从开始日期的月份开始生成账期
            LocalDate periodStart = LocalDate.of(startDate.getYear(), startDate.getMonth(), 1);

            // 计算到当前月份的所有账期
            while (!periodStart.isAfter(currentDate.withDayOfMonth(1))) {
                // 计算账期结束日期
                YearMonth yearMonth = YearMonth.from(periodStart);
                LocalDate periodEnd = yearMonth.atEndOfMonth();

                // 计算计费日期
                LocalDate billingDate = calculateBillingDate(billingMethod, periodStart, periodEnd, startDate, true);

                // 检查计费日期是否已过
                if (!billingDate.isAfter(currentDate)) {
                    // 计算首期是否需要按比例计算
                    boolean isFirstPeriod = periodStart.isEqual(LocalDate.of(startDate.getYear(), startDate.getMonth(), 1));
                    double proportion = calculateProportion(isFirstPeriod, startDate, periodStart, periodEnd);

                    addBillingRecord(records, contract, config, periodStart, periodEnd, billingDate, isFirstPeriod, proportion);

                    // 当月缴下月的首期需要额外生成下一期
                    if (isFirstPeriod && billingMethod == BILLING_METHOD_NEXT_MONTH) {
                        LocalDate nextPeriodStart = periodEnd.plusDays(1);
                        LocalDate nextPeriodEnd = YearMonth.from(nextPeriodStart).atEndOfMonth();
                        LocalDate nextBillingDate = calculateBillingDate(billingMethod, nextPeriodStart, nextPeriodEnd, startDate, false);

                        if (!nextBillingDate.isAfter(currentDate)) {
                            addBillingRecord(records, contract, config, nextPeriodStart, nextPeriodEnd, nextBillingDate, false, 1.0);
                        }
                    }
                }

                // 移动到下一个月
                periodStart = periodStart.plusMonths(1);
            }
        }
    }

    /**
     * 合同月计费处理器
     */
    private class ContractMonthProcessor implements BillingCycleProcessor {
        @Override
        public void process(Contract contract, BillingConfig config, LocalDate currentDate, List<BillingMain> records) {
            LocalDate startDate = config.getStartDate();
            int billingMethod = config.getBillingMethod();
            Integer expenditureId = config.getExpenditureId();

            // 验证费项类型
            if (expenditureId != null) {
                Expenditure expenditure = expenditureMapper.selectById(expenditureId);
                if (expenditure == null ||
                        !Arrays.asList(NATURE_PERIODIC, NATURE_METER).contains(expenditure.getNature())) {
                    logger.warn("费项ID={}类型无效，跳过计费", expenditureId);
                    return;
                }
            }

            // 从开始日期开始生成账期
            LocalDate periodStart = startDate;

            // 生成账期直到当前日期
            while (!periodStart.isAfter(currentDate)) {
                // 计算账期结束日期
                LocalDate nextMonthStart = periodStart.plusMonths(1);
                LocalDate periodEnd;

                // 如果下个月没有相同的日期，则使用下个月的最后一天
                if (nextMonthStart.getDayOfMonth() < periodStart.getDayOfMonth()) {
                    periodEnd = nextMonthStart.minusDays(1);
                } else {
                    periodEnd = nextMonthStart.minusDays(1);
                }

                // 计算计费日期
                LocalDate billingDate = calculateBillingDate(billingMethod, periodStart, periodEnd, startDate, true);

                // 检查计费日期是否已过
                if (!billingDate.isAfter(currentDate)) {
                    // 计算首期是否需要按比例计算
                    boolean isFirstPeriod = periodStart.isEqual(startDate);
                    double proportion = calculateProportion(isFirstPeriod, startDate, periodStart, periodEnd);

                    addBillingRecord(records, contract, config, periodStart, periodEnd, billingDate, isFirstPeriod, proportion);

                    // 当月缴下月的首期需要额外生成下一期
                    if (isFirstPeriod && billingMethod == BILLING_METHOD_NEXT_MONTH) {
                        LocalDate nextPeriodStart = periodEnd.plusDays(1);
                        LocalDate nextPeriodEnd = nextPeriodStart.plusMonths(1).minusDays(1);
                        LocalDate nextBillingDate = calculateBillingDate(billingMethod, nextPeriodStart, nextPeriodEnd, startDate, false);

                        if (!nextBillingDate.isAfter(currentDate)) {
                            addBillingRecord(records, contract, config, nextPeriodStart, nextPeriodEnd, nextBillingDate, false, 1.0);
                        }
                    }
                }

                // 移动到下一个账期
                periodStart = periodEnd.plusDays(1);
            }
        }
    }

    /**
     * 计算计费日期
     */
    private LocalDate calculateBillingDate(int billingMethod, LocalDate periodStart, LocalDate periodEnd, LocalDate configStartDate, boolean isFirstPeriod) {
        switch (billingMethod) {
            case BILLING_METHOD_CURRENT_MONTH:
                return periodEnd;
            case BILLING_METHOD_NEXT_MONTH:
                return isFirstPeriod ? periodStart : periodStart.minusDays(1);
            case BILLING_METHOD_PREVIOUS_MONTH:
                return periodEnd.plusDays(1);
            default:
                logger.warn("未知的缴费方式: {}", billingMethod);
                return periodEnd;
        }
    }

    /**
     * 计算比例
     */
    private double calculateProportion(boolean isFirstPeriod, LocalDate startDate, LocalDate periodStart, LocalDate periodEnd) {
        if (!isFirstPeriod || startDate.isEqual(periodStart)) {
            return 1.0;
        }

        long daysInPeriod = ChronoUnit.DAYS.between(periodStart, periodEnd) + 1;
        long daysToBill = ChronoUnit.DAYS.between(startDate, periodEnd) + 1;

        return (double) daysToBill / daysInPeriod;
    }

    /**
     * 添加计费记录（从配置中获取三表信息）
     */
    private void addBillingRecord(List<BillingMain> records, Contract contract,
                                  BillingConfig config, LocalDate periodStart, LocalDate periodEnd,
                                  LocalDate billingDate, boolean isFirstPeriod, double proportion) {
        // 检查是否已存在相同账期的记录
        String billingPeriod = periodStart.format(PERIOD_FORMATTER);
        if (isRecordExists(contract.getContractId(), billingPeriod)) {
            logger.debug("已存在合同ID={},账期={}的计费记录，跳过生成", contract.getContractId(), billingPeriod);
            return;
        }

        BillingMain record = new BillingMain();
        record.setContractId(contract.getContractId());
        record.setBillingPeriod(billingPeriod);

        // 根据费项性质计算应收金额
        Integer expenditureId = config.getExpenditureId();
        if (expenditureId != null && isMeterExpenditure(expenditureId)) {
            // 三表计费：根据抄表记录计算
            try {
                // 使用YearMonth解析账期并获取当月第一天和最后一天
                YearMonth yearMonth = YearMonth.parse(billingPeriod, PERIOD_FORMATTER);
                LocalDate periodStartDate = yearMonth.atDay(1);
                LocalDate periodEndDate = yearMonth.atEndOfMonth();

                ReadingRecord readingRecord = getValidReadingRecord(config.getTableId(), periodStartDate, periodEndDate);
                if (readingRecord != null) {
                    // 计算用量
                    ThreeTables threeTable = threeTablesMapper.selectById(config.getTableId());
                    if (threeTable != null) {
                        BigDecimal usage = calculateUsage(readingRecord, threeTable.getMagnification());
                        if (usage != null && usage.compareTo(BigDecimal.ZERO) > 0) {
                            // 根据计费公式计算金额
                            record.setReceivableAmount(calculateAmountByFormula(
                                    config.getFeeFormula(), usage, config.getUnitPrice()
                            ));
                        }
                    }
                }
            } catch (Exception e) {
                logger.error("计算三表计费金额失败，合同ID={},账期={}",
                        contract.getContractId(), billingPeriod, e);
                // 发生异常时使用默认单价计算
                record.setReceivableAmount(config.getUnitPrice().multiply(BigDecimal.valueOf(proportion)));
            }
        }

        // 如果未通过公式计算，则使用默认单价
        if (record.getReceivableAmount() == null) {
            record.setReceivableAmount(config.getUnitPrice().multiply(BigDecimal.valueOf(proportion)));
        }

        record.setStatus(1);
        record.setCreateTime(LocalDateTime.now());
        record.setLastModifiedTime(LocalDateTime.now());
        record.setRemark(isFirstPeriod ? "首期" : "");
        record.setUserId(0);
        record.setCustomerId(contract.getCustomerId());
        record.setOrganizationName(contract.getResourceName());
        record.setProjectName(contract.getResourceName());
        record.setBuildingName(contract.getResourceName());
        record.setFloorName(contract.getResourceName());
        record.setCategoryId(contract.getCategoryId());
        record.setExpenditureId(expenditureId);

        records.add(record);
    }

    /**
     * 根据计费公式计算金额
     */
    private BigDecimal calculateAmountByFormula(String formula, BigDecimal usage, BigDecimal unitPrice) {
        if (formula == null || formula.trim().isEmpty()) {
            return usage.multiply(unitPrice);
        }

        // 简单公式解析，实际应用中可能需要更复杂的解析器
        try {
            // 示例公式格式: "用量 * 单价" 或 "用量 * 单价 + 固定费用"
            if (formula.contains("用量") && formula.contains("单价")) {
                formula = formula.replace("用量", usage.toPlainString());
                formula = formula.replace("单价", unitPrice.toPlainString());

                // 简单的表达式计算
                return evaluateExpression(formula);
            }

            // 默认使用用量 * 单价
            return usage.multiply(unitPrice);
        } catch (Exception e) {
            logger.error("计费公式解析错误: {}", formula, e);
            return usage.multiply(unitPrice);
        }
    }

    /**
     * 计算简单表达式
     */
    private BigDecimal evaluateExpression(String expression) {
        // 这里使用简单的表达式解析，实际应用中可能需要更复杂的解析器
        try {
            // 移除所有空格
            expression = expression.replaceAll("\\s+", "");

            // 简单的四则运算解析
            if (expression.contains("+")) {
                String[] parts = expression.split("\\+");
                return evaluateExpression(parts[0]).add(evaluateExpression(parts[1]));
            } else if (expression.contains("-")) {
                String[] parts = expression.split("-");
                return evaluateExpression(parts[0]).subtract(evaluateExpression(parts[1]));
            } else if (expression.contains("*")) {
                String[] parts = expression.split("\\*");
                return evaluateExpression(parts[0]).multiply(evaluateExpression(parts[1]));
            } else if (expression.contains("/")) {
                String[] parts = expression.split("/");
                return evaluateExpression(parts[0]).divide(evaluateExpression(parts[1]), 2, BigDecimal.ROUND_HALF_UP);
            }

            // 如果不是运算表达式，直接转换为BigDecimal
            return new BigDecimal(expression);
        } catch (Exception e) {
            logger.error("表达式计算错误: {}", expression, e);
            return BigDecimal.ZERO;
        }
    }

    /**
     * 检查是否已存在相同账期的记录
     */
    private boolean isRecordExists(Long contractId, String billingPeriod) {
        Integer count = billingMainMapper.selectCount(
                new QueryWrapper<BillingMain>()
                        .eq("contract_id", contractId)
                        .eq("billing_period", billingPeriod)
        );
        return count != null && count > 0;
    }

    /**
     * 将计费记录保存到计费主表（批量插入）
     */
    private void saveBillingRecordsToMainTable(List<BillingMain> records) {
        if (records.isEmpty()) {
            return;
        }

        // 分批插入，每批不超过BATCH_SIZE条
        for (int i = 0; i < records.size(); i += BATCH_SIZE) {
            List<BillingMain> batch = records.subList(i, Math.min(i + BATCH_SIZE, records.size()));
            try {
                this.saveBatch(batch, BATCH_SIZE);
                logger.info("成功插入{}条计费记录", batch.size());
            } catch (Exception e) {
                logger.error("批量插入计费记录失败，尝试单条插入", e);
                // 批量插入失败时尝试单条插入
                for (BillingMain record : batch) {
                    try {
                        billingMainMapper.insert(record);
                    } catch (Exception ex) {
                        logger.error("插入单条计费记录失败，合同ID={},账期={}",
                                record.getContractId(), record.getBillingPeriod(), ex);
                    }
                }
            }
        }
    }
}